/* 
 * File:   BruitPerlin.cpp
 * Author: dang
 * 
 * Created on 5 juin 2010, 23:50
 */

/*
 * BrutPerlin.cpp
 *
 *  Created on: 13 mai 2010
 *      Author: dang
 */
#include <stdio.h>
#include <stdlib.h>
#include "iostream"
#include "BruitPerlin.h"
#include "math.h"


int interpolate(int y1, int y2, int n, int delta){
	if (n==0)
	    return y1;
	if (n==1)
	    return y2;

	float a = (float)delta/n;

	float v1 = 3*pow(1-a, 2) - 2*pow(1-a,3);
	float v2 = 3*pow(a, 2)   - 2*pow(a, 3);

	return y1*v1 + y2*v2;
}

int BruitPerlin::valeur_interpolee(int i, int j, int frequence) const {
	int borne1x, borne1y, borne2x, borne2y, q;
	float pas_width;
	pas_width = (float)this->width / (float)frequence;

        float pas_heigth;
	pas_heigth = (float)this->height / (float)frequence;

	q = (float)i/pas_width;
	borne1x = q*pas_width;
	borne2x = (q+1)*pas_width;

	if(borne2x >= this->width)
		borne2x = this->width-1;

	q = (float)j/pas_heigth;
	borne1y = q*pas_heigth;
	borne2y = (q+1)*pas_heigth;

	if(borne2y >= this->height)
		borne2y = this->height -1;

	int b00,b01,b10,b11;
	b00 = this->random[borne1x][borne1y];
	b01 = this->random[borne1x][borne2y];
	b10 = this->random[borne2x][borne1y];
	b11 = this->random[borne2x][borne2y];

	int v1  = interpolate(b00, b01, borne2y-borne1y, j-borne1y);
	int v2  = interpolate(b10, b11, borne2y-borne1y, j-borne1y);
	int fin = interpolate(v1, v2, borne2x-borne1x , i-borne1x);

	return fin;
}

unsigned char BruitPerlin::aleatoire(float a) {
	return (float)rand() / RAND_MAX * a;
}

BruitPerlin::BruitPerlin(int width, int height, float persistance, int octaves, int frequence,
        int xmin, int xmax, int ymin, int ymax) :
Fractal(xmin, xmax, ymin, ymax){
	this->width = width;
        this->height = height;
	this->persistance = persistance;
	this->octaves = octaves;
	this->frequence = frequence;
        for (int i=0; i< width ; i++){
		std::vector<int> tmp (height, 0);
		this->random.push_back(tmp);
	}
	int i,j;
	for (i = 0; i< width ; i++){
		for (j=0; j < height; j++)
		{
			this->random[i][j] = aleatoire(256);
		}
	}

     	float persistance_courante = persistance;
        for (i=0; i<octaves; i++){
            persistances.push_back(persistance_courante);
            persistance_courante*=persistance;
        }
        sum_persistance = 0.;
        for (i=0; i<octaves; i++)
           sum_persistance += persistances[i];

        int f_courante = frequence;
        for (int n=0; n<octaves; n++){
            frequences.push_back(f_courante);
            f_courante *= frequence;
        }
}

BruitPerlin::~BruitPerlin() {
}

int BruitPerlin::get_octaves() const
{
    return octaves;
}

std::vector<int> BruitPerlin::get_frequences() const
{
    return frequences;
}

std::vector<float> BruitPerlin::get_persistances() const
{
    return persistances;
}

float BruitPerlin::get_sumpersitance() const
{
	return sum_persistance;
}
Uint32 BruitPerlin::obtenirCouleur(double gris) {
   return (((int) (gris * 255)) << 16) + (((int) (gris * 255)) << 8) + (int) (gris * 255);
}

Uint32 BruitPerlin::obtenirCouleurjolie(double rouge, double vert, double bleu) {
   return (((int) (rouge * 255)) << 16) + (((int) (vert * 255)) << 8) + ((int) (bleu * 255));
}

Uint32 BruitPerlin::compute(const double x, const double y) const {
    Uint32 iter = 0;
    for (int n = 0; n < this->get_octaves(); n++)
    {
        iter += this->valeur_interpolee(x, y, this->get_frequences()[n]) * (this->get_persistances()[n]);
    }
    return (iter / this->get_sumpersitance());
}